package rc.database.GetSuperior;

import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.AuthorityType;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.namespace.QName;
import org.apache.log4j.Logger;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.extensions.webscripts.AbstractWebScript;
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.WebScriptResponse;
import rc.database.connection.MyDBOperations;

import java.io.IOException;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * Created by IntelliJ IDEA.
 * User: Slejus
 * Date: 13.11.19
 * Time: 15.17
 * To change this template use File | Settings | File Templates.
 */
public class NewGetSuperiorIdWebScript extends AbstractWebScript{

    private static final Logger logger = Logger.getLogger(NewGetSuperiorIdWebScript.class);

    static final String NAMESPACE = "http://*.kada.lt/model/people/1.0";
    static final QName PROP_VAR_ID = QName.createQName(NAMESPACE, "personVarId");

    private PersonService personService;
    private NodeService nodeService;
    private AuthorityService authorityService;


    public void setAuthorityService(AuthorityService authorityService) {
        this.authorityService = authorityService;
    }

    public void setPersonService(PersonService personService) {
        this.personService = personService;
    }

    public void setNodeService(NodeService nodeService) {
        this.nodeService = nodeService;
    }

    @Override
    public void execute(WebScriptRequest webScriptRequest, WebScriptResponse webScriptResponse) throws IOException {
        List<UserData> alternativeUsers = new ArrayList<UserData>();
        List<UserData> usersFromDb = new ArrayList<UserData>();
        List<UserData> allUsers = new ArrayList<UserData>();
        UserData superior = new UserData();

        int var_id = 0;

        String username = org.alfresco.repo.security.authentication.AuthenticationUtil.getFullyAuthenticatedUser();
        logger.debug("Logged user: " + username);

        if(personService != null && nodeService != null && authorityService != null && username != null) {
            String usrGroup = webScriptRequest.getParameter("group");
            logger.debug("Alfresco group parameter: " + usrGroup);

            NodeRef personNode = personService.getPerson(username);
            logger.debug("LOGGED PERSON ID: " + nodeService.getProperty(personNode, PROP_VAR_ID));
            logger.debug("NODEREF: " + personNode);
            logger.debug("FIRSTNAME: " + nodeService.getProperty(personNode, ContentModel.PROP_FIRSTNAME));
            logger.debug("LASTNAME: " + nodeService.getProperty(personNode, ContentModel.PROP_LASTNAME));

            if (nodeService.getProperty(personNode, PROP_VAR_ID) != null) {
                String currentUserId = nodeService.getProperty(personNode, PROP_VAR_ID).toString();
                var_id = Integer.parseInt(currentUserId);
            }

            if (var_id > 0) {
                superior = getCurrentUserSuperior(var_id, superior);
                alternativeUsers = getListOfAlternativeUsers(var_id, usersFromDb, alternativeUsers);

                if (usrGroup != null && !usrGroup.isEmpty()) {
                    String group = "GROUP_" + usrGroup;
                    allUsers = getAlfrescoGroupUsers(group, allUsers);
                }
                logger.debug("Alternative USERS: " + alternativeUsers.toArray());
                logger.debug("Alfresco USERS: " + allUsers.toArray());
                logger.debug("Superior: " + superior.getUserId()+ " " + superior.getFirstName()+ " " + superior.getLastName());

                if (alternativeUsers != null && !alternativeUsers.isEmpty()) {
                    for (UserData usr : alternativeUsers){
                        boolean isDuplicate = false;
                        for (UserData altUser : allUsers) {
                            logger.debug("usr ref:" + usr.getUserRef()+"  altUser ref: " + altUser.getUserRef());
                            if (usr.getUserRef().equals(altUser.getUserRef())) {
                                isDuplicate = true;
                                logger.debug("DUPLICATE USER: " + usr.getFirstName() + " " + usr.getLastName() + " " + usr.getLastName() );
                                break;
                            }
                        }
                        if (!isDuplicate) {
                            allUsers.add(usr);
                            logger.debug("ADDED TO ALF USER: " + usr.getFirstName() + " " + usr.getLastName() + " " + usr.getLastName() );
                        }
                    }
                }

                try {
                    putToResponse(webScriptResponse, createJsonDataObj(superior, allUsers));
                } catch (JSONException e) {
                    e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                    logger.debug(e);
                }


            } else {
                try {
                    badResponse(webScriptResponse);
                } catch (JSONException e) {
                    e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                    logger.debug(e);
                }
            }

        } else {
            logger.debug("Services not found!");
            try {
                badResponse(webScriptResponse);
            } catch (JSONException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                logger.debug(e);
            }
        }
    }

    private UserData getCurrentUserSuperior(int var_id, UserData superior) {
        ResultSet rs = null; Connection conn = null; Statement stmt = null;

        if (var_id > 0) {
            try {
                MyDBOperations db = new MyDBOperations("jussle","E4fc6b54","jdbc:oracle:thin:@kadadev.kada.lan:1521/kadadev","oracle.jdbc.OracleDriver");
                Class.forName(db.getJdbcDriver());
                conn = DriverManager.getConnection(db.getJdbcUrl(), db.getUserName(), db.getPassword());
                conn.setAutoCommit(false);
                stmt = conn.createStatement();
                rs = stmt.executeQuery(db.getSuperior(var_id));
                if (rs.next()) {
                    superior.setUserId(rs.getInt(1));
                    superior.setFirstName(rs.getString(2));
                    superior.setLastName(rs.getString(3));
                    logger.debug("SUPERIOR DATA: " + superior.getUserId() + " " + superior.getFirstName() + " " + superior.getLastName());
                    superior = getAlfrescoUserData(superior);
                }
            }
            catch (ClassNotFoundException ex) {logger.debug(ex);}
            catch (SQLException ex) {logger.debug(ex);}
            catch (JSONException e) {e.printStackTrace(); logger.debug(e);}
            catch (IOException e) {e.printStackTrace(); logger.debug(e);}
            finally {
                if (rs != null) {
                    try {rs.close();}
                    catch (SQLException e) {logger.debug(e);}
                }
                if (stmt != null) {
                    try {stmt.close();}
                    catch (SQLException e) {logger.debug(e);}
                }
                if (conn != null) {
                    try {conn.close();}
                    catch (SQLException e) {logger.debug(e);}
                }
            }
        }

        return superior;
    }

    private UserData getAlfrescoUserData(UserData superior) throws IOException, JSONException {
        String strUserId;
        Set<NodeRef> allAlfrescoUsers =  personService.getAllPeople();

        if (allAlfrescoUsers.size() > 0) {
            for (NodeRef personRef : allAlfrescoUsers) {
                if (nodeService.getProperty(personRef, PROP_VAR_ID) != null) {
                    strUserId = nodeService.getProperty(personRef, PROP_VAR_ID).toString();
                    int userId = Integer.parseInt(strUserId);
                    logger.debug("userId = " + userId + "  vad_id = " + superior.getUserId());
                    if (userId == superior.getUserId())
                    {
                        superior.setFirstName(nodeService.getProperty(personRef, ContentModel.PROP_FIRSTNAME).toString());
                        superior.setLastName(nodeService.getProperty(personRef, ContentModel.PROP_LASTNAME).toString());
                        superior.setUserRef(personRef.toString());
                        logger.debug("FULL SUPERIOR DATA: " + superior.getUserId()+ " " + superior.getFirstName()+ " " + superior.getLastName()+ " " + superior.getUserRef());
                        break;
                    }
                }
            }
        } else logger.debug("No alfresco users founded");

        return superior;
    }

    private List<UserData> getListOfAlternativeUsers(int var_id, List<UserData> usersFromDb, List<UserData> alternativeUsers) {
        ResultSet rs = null; Connection conn = null; Statement stmt = null;
        try {
            MyDBOperations db = new MyDBOperations("jussle","E4fc6b54","jdbc:oracle:thin:@kadadev.kada.lan:1521/kadadev","oracle.jdbc.OracleDriver");
            Class.forName(db.getJdbcDriver());
            conn = DriverManager.getConnection(db.getJdbcUrl(), db.getUserName(), db.getPassword());
            conn.setAutoCommit(false);
            stmt = conn.createStatement();
            rs = stmt.executeQuery(db.getAlternativeUsers(var_id));
            while (rs.next()) {
                usersFromDb.add(new UserData(rs.getString(2), rs.getString(3), rs.getInt(1)));
            }
            logger.debug("Alternative Users From DB: " + usersFromDb.toArray());
            alternativeUsers = getAlternativeAlfrescoUsers(usersFromDb, alternativeUsers);
        }
        catch (ClassNotFoundException ex) {logger.debug(ex);}
        catch (SQLException ex) {logger.debug(ex);}
        finally {
            if (rs != null) {
                try {rs.close();}
                catch (SQLException e) {logger.debug(e);}
            }
            if (stmt != null) {
                try {stmt.close();}
                catch (SQLException e) {logger.debug(e);}
            }
            if (conn != null) {
                try {conn.close();}
                catch (SQLException e) {logger.debug(e);}
            }
        }

        return alternativeUsers;
    }

    private List<UserData> getAlternativeAlfrescoUsers(List<UserData> usersFromDb, List<UserData> alternativeUsers) {
        logger.debug("UsersFromDb size: " + usersFromDb.size());
        logger.debug("UsersFromDb data: " + usersFromDb.toArray());
        Set<NodeRef> allAlfrescoUsers =  personService.getAllPeople();
        if (allAlfrescoUsers != null && !allAlfrescoUsers.isEmpty()) {
            logger.debug("Alfresco users size: " + allAlfrescoUsers.size());
            for (NodeRef personRef : allAlfrescoUsers) {
                if (nodeService.getProperty(personRef, PROP_VAR_ID) != null) {
                    logger.debug("Alt user id: " + nodeService.getProperty(personRef, PROP_VAR_ID));
                    String var_id = (nodeService.getProperty(personRef, PROP_VAR_ID)).toString();
                    if (var_id != null && !var_id.isEmpty()) {
                        for(UserData usr : usersFromDb) {
                            int usrId = usr.getUserId();
                            if (usrId == Integer.parseInt(var_id)) {
                                logger.debug("Founded match for alternativeUser: " + var_id);
                                String name = nodeService.getProperty(personRef, ContentModel.PROP_FIRSTNAME).toString();
                                String lastname = nodeService.getProperty(personRef, ContentModel.PROP_LASTNAME).toString();
                                String noderef = personRef.toString();
                                alternativeUsers.add(new UserData(name, lastname, noderef, usr.getUserId()));
                                logger.debug("Alternative user: "+ usr.getUserId()+ " " + name+ " " + lastname + " " + noderef);
                                break;
                            }
                        }
                    }
                }
            }
        } else logger.debug("No users founded");

        return alternativeUsers;
    }

    private List<UserData> getAlfrescoGroupUsers(String group, List<UserData> allUsers){
        logger.debug("Alfresco Group: " + group);
        Set<String> groupUsersAll = authorityService.getContainedAuthorities(AuthorityType.USER, group, false);
        int groupSize = groupUsersAll.size();
        logger.debug("Alfresco group "+ group + " size: " + groupSize);
        if (groupSize > 0) {
            for (String authority : groupUsersAll) {
                NodeRef person = personService.getPerson(authority);
                String name = nodeService.getProperty(person, ContentModel.PROP_FIRSTNAME).toString();
                String surname = nodeService.getProperty(person, ContentModel.PROP_LASTNAME).toString();
                String noderef = person.toString();
                logger.debug("Alfresco user: " + name + " " + surname + " " + noderef);
                allUsers.add(new UserData(name, surname, noderef));
            }
        }

        return allUsers;
    }

    private JSONArray createJsonDataObj(UserData superior, List<UserData> allUsers) throws JSONException {
        List<JSONObject> objArr = new ArrayList<JSONObject>();
        JSONArray arr = new JSONArray();


        if (superior.getUserRef() != null && (superior.getFirstName() != null || superior.getLastName() != null))
        {
            objArr.add(new JSONObject().put("isDefault","true").put("firstName",superior.getFirstName()).put("lastName", superior.getLastName()).put("userId",superior.getUserRef()));
        } else {
            logger.debug("Superior not found");
        }

        if (!allUsers.isEmpty() && allUsers != null) {
            int listSize = allUsers.size();
            logger.debug("altUsers list size: " + listSize);
            for (int i = 0; i < listSize; i++)
            {
                if (!allUsers.get(i).getUserRef().equals(superior.getUserRef())) {
                    objArr.add(new JSONObject().put("isDefault","false").put("firstName",allUsers.get(i).getFirstName()).put("lastName", allUsers.get(i).getLastName()).put("userId",allUsers.get(i).getUserRef()));
                    logger.debug("Alternative user: " + objArr.get(i));
                } else {
                    logger.debug("DUPLICATE USER: " + allUsers.get(i).getFirstName() + " " + allUsers.get(i).getLastName());
                }
            }
        }
        int objSize = objArr.size();
        for (int j = 0; j < objSize; j++) {
            arr.put(objArr.get(j));
        }

        logger.debug("User to select:"  + arr);
        return arr;
    }

    private void badResponse(WebScriptResponse webScriptResponse) throws JSONException, IOException {
        JSONObject object = new JSONObject();
        object.put("members", "none");
        String jsonString = object.toString();
        logger.debug(jsonString);
        webScriptResponse.setContentType("application/json; charset=utf-8");
        webScriptResponse.getWriter().write(jsonString);
    }

    private void putToResponse(WebScriptResponse webScriptResponse, JSONArray arr) throws JSONException, IOException {
        if (arr != null) {
            JSONObject object = new JSONObject();
            object.put("members", arr);
            String jsonString = object.toString();
            logger.debug(jsonString);
            webScriptResponse.setContentType("application/json; charset=utf-8");
            webScriptResponse.getWriter().write(jsonString);
        } else {
            logger.debug("JSONArray is null");
            badResponse(webScriptResponse);
        }
    }

}

class UserData
{
    private String alfFirstName;
    private String alfLastName;
    private String alfUserRef;
    private int alfUserId;

    public UserData(String fName, String lName, String ref, int id)
    {
        this.alfFirstName = fName;
        this.alfLastName = lName;
        this.alfUserRef = ref;
        this.alfUserId = id;
    }

    public UserData(String fName, String lName, String ref) {
        this.alfFirstName = fName;
        this.alfLastName = lName;
        this.alfUserRef = ref;
    }

    public UserData(String fName, String lName, int id) {
        this.alfFirstName = fName;
        this.alfLastName = lName;
        this.alfUserId = id;
    }

    public UserData(){}

    public String getFirstName() {
        return this.alfFirstName;
    }

    public String getLastName() {
        return this.alfLastName;
    }

    public String getUserRef() {
        return this.alfUserRef;
    }

    public int getUserId() {
        return this.alfUserId;
    }

    public void setFirstName(String alfFirstName) {
        this.alfFirstName = alfFirstName;
    }

    public void setLastName(String alfLastName) {
        this.alfLastName = alfLastName;
    }

    public void setUserRef(String alfUserRef) {
        this.alfUserRef = alfUserRef;
    }

    public void setUserId(int alfUserId) {
        this.alfUserId = alfUserId;
    }

    public Boolean isEmpty() {
        if (this.alfUserRef.isEmpty() || this.alfUserRef == null) {
            return true;
        } else return false;
    }

}
